home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / wordproc / hshell1.arj / CPROG.HYP / cprog.HXP
Text File  |  1993-12-29  |  16KB  |  873 lines

  1. /*
  2. .REMARK
  3.     Example C program source file set up as a hyperfile
  4.     The C Program is in the public domain
  5.  
  6.     WARNING: - Program is from Unix system and will need
  7.            modification to compile and run on MSDOS
  8.          - The program must not be edited using HE
  9.          - SETUP script must not be longer than 199 lines
  10.  
  11. .HEADER
  12. ~DRFile: $3  Function: $1  [$2]~DT
  13.  
  14. .FOOTER
  15.  
  16. [d]  ~NDeclarations~PA@MDeclarations~Kd~E   [ ]  ~A-- Press space to continue --~Pk# ~K ~E   [r]  ~A"Return"~PB~Kr~E
  17. .SCRIPT SETUP
  18. K# F+
  19. O43
  20. ZANBraces:NGlobals A
  21. ZANLineNumber:NGlobals A
  22. ZANPageNumber:NGlobals A
  23. ZANPageLength:NGlobals A
  24. ZANPagePart:NGlobals A
  25. ZANPageEnd:NGlobals A
  26. ZANSawFunction:NGlobals A
  27. ZANInComment:NGlobals A
  28. ZANInString:NGlobals A
  29. ZANFileLineNumber:NGlobals A
  30. ZANProgName:NGlobals A
  31. ZANToday:NGlobals A
  32. ZANCurrentName:NGlobals A
  33. ZANFunctionName:NGlobals B
  34. ZANFileDate:NGlobals B
  35. ZANSortFlag:NGlobals B
  36. ZANNumberFlag:NGlobals B
  37. ZANSpace_to_leave:NGlobals B
  38. ZANTabWidth:NGlobals B
  39. ZANToc:NGlobals B
  40. ZANTocPages:NGlobals B
  41. ZANTocCount:NGlobals B
  42. ZANSaveOut:NGlobals B
  43. ZANTempName:NGlobals B
  44. ZANTemp2Name:NGlobals B
  45. ZANBP:NDefines
  46. ZANTOC_SIZE:NDefines
  47. ZANNEWFILE:NDefines
  48. ZANNEWFUNCTION:NDefines
  49. ZANisidchr:NDefines
  50. .
  51. .MENU Declarations
  52. Includes|NIncludes
  53. Defines|NDefines
  54. Externals|NExternals
  55. Globals A|NGlobals A
  56. Globals B|NGlobals B
  57. .
  58. */
  59. /*
  60. .NOTE Includes
  61. */
  62.  
  63. #include <sys/types.h>
  64. #include <sys/stat.h>
  65. #include <stdio.h>
  66. #include <ctype.h>
  67. #include <signal.h>
  68. #include <string.h>
  69.  
  70. /*
  71. .NOTE Defines
  72. */
  73. #define BP        0xC        /* Form feed            */
  74. #define TOC_SIZE    4096
  75. #define    NEWFILE        1
  76. #define NEWFUNCTION    2
  77.  
  78. #define isidchr(c)    (isalnum(c) || (c == '_'))
  79.  
  80. /*
  81. .NOTE Externals
  82. */
  83.  
  84. extern int errno;    /* system error number */
  85. extern char *sys_errlist[];    /* error message */
  86.  
  87. /*
  88. .NOTE Globals A
  89. */
  90. FILE    *File;
  91. int    Braces;                /* Keeps track of brace depth    */
  92. int    LineNumber;            /* Count output lines        */
  93. int    PageNumber = 0;            /* You figure this one out    */
  94. int    PageLength = 66;        /* -l <len> Normal paper length    */
  95. int    PagePart = 12;            /* Decision on paging for new fn*/
  96. int    PageEnd;            /* Accounts for space at bottom    */
  97. int    SawFunction;
  98. int    InComment;
  99. int    InString;
  100.  
  101. long    FileLineNumber;            /* Input file line number    */
  102.  
  103. char    *ProgName;
  104. char    Today[30];
  105. char    *CurrentName;                /* Current file name        */
  106. /*
  107. .NOTE Globals B
  108. */
  109. char    FunctionName[80];
  110. char    FileDate[24];            /* Last modified time of file    */
  111.  
  112. char    SortFlag;            /* -s == sort table of contents    */
  113. char    NumberFlag;            /* -n == output line numbers    */
  114. int    Space_to_leave = 5;        /* -r<number> space to leave    */
  115. int    TabWidth = 0;            /* -t <number> width of tabs     */
  116.  
  117. char    *Toc[TOC_SIZE];
  118. int    TocPages[TOC_SIZE];
  119. int    TocCount;
  120.  
  121. int    SaveOut;
  122. char    *TempName;
  123. char    *Temp2Name;
  124.  
  125. /*
  126. .FRAME Introduction
  127.  *      This program prints the files named in its argument list, preceding
  128.  *    the output with a table of contents. Each file is assumed to be C
  129.  *    source code (but doesn't have to be) in that the program searches
  130.  *    for the beginning and end of functions. Function names are added to
  131.  *    the table of contents, provided the name starts at the beginning of
  132.  *    a line. The function name in the output is double striken.
  133.  *
  134.  *    By default blank space is inserted after every closing '}'
  135.  *    character. Thus functions and structure declarations are nicely
  136.  *    isolated in the output. The only drawback to this is that structure
  137.  *    initialization tables sometimes produce lots of white space.
  138.  *    The "-r" option removes this space, or changes it to the indicated
  139.  *    length.
  140.  *
  141.  *    The option "-l" indicates that the following argument is to be
  142.  *    the page length used for output (changing the page length hasn't been
  143.  *    tested much).
  144.  *
  145.  *    The option "-s" indicates that the table of contents should be sorted
  146.  *    by function name within each file.
  147.  *
  148.  *    The option "-n" indicates that output lines should be numbered with
  149.  *    the corresponding line number from the input file.
  150.  *
  151.  *    The option "-p" indicates what proportion of the page in steps of 16
  152.  *    should be used for deciding if a new function needs a new page.
  153.  *    That is -p12 (the default) indicates that if a function starts
  154.  *    within the top 12/16 (3/4) of the page then do it, otherwise put it
  155.  *    on a new page.  Thus the higher the number (upto 16) the closer to
  156.  *    the bottom of the page will functions be started. -p0 says put each
  157.  *    func on a new page.
  158.  *
  159.  *    Written by:
  160.  *        Paul Breslin
  161.  *        Human Computing Resources Corp.
  162.  *        10 St. Mary St.
  163.  *        Toronto, Ontario
  164.  *        Canada, M4Y 1P9
  165.  *
  166.  *    Careful:
  167.  *        It will find things like  struct foo *f()...
  168.  *        but not things like     int
  169.  *                    f
  170.  *                    ()...
  171.  *        ie. the constraint is that the () must appear on the same line
  172.  *        as the function name.
  173.  */
  174. /*
  175. .FRAME main
  176. .TITLE Control function
  177. */
  178. main(argc, argv)
  179. char    **argv;
  180.   {
  181.     register int    i;
  182.     char        *ctime();
  183.     time_t        thetime, time();
  184.     char        *parm;
  185.     int        c;
  186.  
  187.     ProgName = argv[0];
  188.     thetime     = time((time_t *)0);
  189.     strcpy(Today,ctime(&thetime));
  190.  
  191.     for( i=1; argc > i; ++i )
  192.       {
  193.         if( argv[i][0] != '-' 
  194.         ||  argv[i][1] == '\0' ) break;
  195.  
  196.         parm = argv[i];
  197.         while( c = *++parm ) switch( c ){
  198.             case 't':
  199.             if( argc < 3 ) Usage();
  200.             TabWidth = atoi(argv[++i]);
  201.             if( TabWidth < 0 )
  202.                 TabWidth = 0;
  203.             break;
  204.  
  205.             case 'l':
  206.             if( argc < 3 ) Usage();
  207.             PageLength = atoi(argv[++i]);
  208.             break;
  209.  
  210.             case 's':
  211.             ++SortFlag;
  212.             break;
  213.  
  214.             case 'n':
  215.             ++NumberFlag;
  216.             break;
  217.  
  218.             case 'r':
  219.             if( (c = parm[1]) && isdigit( c )
  220.                 &&( c = atoi( parm+1 )) > 0 ){
  221.                 Space_to_leave = c;
  222.             } else {
  223.                 Space_to_leave = 0;
  224.             }
  225.             while( *parm ){
  226.                 ++parm;
  227.             }
  228.             --parm;
  229.             break;
  230.  
  231.             case 'p':
  232.             if( (c = parm[1]) && isdigit( c )
  233.                 &&( c = atoi( parm+1 )) >= 0 ){
  234.                 PagePart = (c <= 16) ? c: 16;
  235.             }
  236.             while( *parm ){
  237.                 ++parm;
  238.             }
  239.             --parm;
  240.             break;
  241.  
  242.             default:
  243.             Usage();
  244.             break;
  245.           }
  246.       }
  247.     PageEnd = PageLength - ((PageLength > 30) ? 2 : 1);
  248.  
  249.     StartTempFile();
  250.  
  251.     if( i == argc )
  252.       {                /* no file names */
  253.         File = stdin;
  254.         CurrentName = "Standard Input";
  255.         List();
  256.       }
  257.  
  258.     for(; i < argc; ++i )
  259.       {
  260.         if( strcmp(argv[i], "-") == 0 )
  261.           {
  262.             File = stdin;
  263.             CurrentName = "Standard Input";
  264.           }
  265.         else
  266.           {
  267.             if( (File = fopen( CurrentName = argv[i], "r" )) == NULL )
  268.               {
  269.             fprintf(stderr,"%s: Can't open file '%s': %s\n",
  270.                     ProgName, CurrentName, sys_errlist[errno] );
  271.                 continue;
  272.               }
  273.           }
  274.         List();
  275.         if( File != stdin ) fclose(File);
  276.       }
  277.  
  278.     if( PageNumber > 1 || LineNumber > 0 )
  279.         putchar(BP);
  280.     EndTempFile();
  281.  
  282.     DumpTableOfContents();
  283.     DumpTempFiles();
  284.     Done();
  285.   }
  286. /*
  287. .FRAME Usage
  288. .TITLE Print program usage
  289. */
  290. Usage()
  291.   {
  292.     fprintf(stderr, "Usage: %s [-n] [-t tabwidth] [-p[num]] [-r[num]] [-s] [-l pagelength] [files] [-]\n",
  293.         ProgName);
  294.     exit(1);
  295.   }
  296.  
  297. /*
  298. .FRAME StartTempFile
  299. .TITLE Open temporary file
  300. */
  301. StartTempFile()
  302.   {
  303.     int        Done();
  304.     extern char    *mktemp();
  305.  
  306.     CatchSignalsPlease(Done);
  307.  
  308.     SaveOut  = dup(1);
  309.     TempName = mktemp("/tmp/cprXXXXXX");
  310.     if( freopen(TempName, "w", stdout) == NULL )
  311.       {
  312.         fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
  313.             TempName, sys_errlist[errno]);
  314.         exit(1);
  315.       }
  316.   }
  317.  
  318. /*
  319. .FRAME EndTempFile
  320. .TITLE Handle temporary file
  321. */
  322. EndTempFile()
  323.   {
  324.     Temp2Name = mktemp("/tmp/CPRXXXXXX");
  325.     if( freopen(Temp2Name, "w", stdout) == NULL )
  326.       {
  327.         fprintf(stderr, "%s: Can't open temp file '%s': %s\n", ProgName,
  328.             Temp2Name, sys_errlist[errno]);
  329.         exit(1);
  330.       }
  331.   }
  332.  
  333. /*
  334. .FRAME DumpTempFiles
  335. .TITLE Output from temporary area
  336. */
  337. DumpTempFiles()
  338.   {
  339.     register int    pid, w;
  340.  
  341.     fclose(stdout);
  342.     dup(SaveOut);
  343.  
  344.     while( (pid = fork()) < 0 ) sleep(1);
  345.     if( pid )
  346.         while ((w = wait(0)) != pid  &&  w != -1);
  347.     else
  348.       {
  349.         CatchSignalsPlease(SIG_DFL);
  350.  
  351.         execl( "/bin/cat", "cat", Temp2Name, TempName, 0 );
  352.         fprintf(stderr, "%s: exec of /bin/cat failed: %s\n", ProgName,
  353.             sys_errlist[errno]);
  354.         exit(0);
  355.       }
  356.   }
  357.  
  358. /*
  359. .FRAME Done
  360. .TITLE Finished
  361. */
  362. Done()
  363.   {
  364.     CatchSignalsPlease(SIG_IGN);
  365.  
  366.     if( TempName )  unlink( TempName );
  367.     if( Temp2Name ) unlink( Temp2Name );
  368.  
  369.     exit(0);
  370.   }
  371.  
  372. /*
  373. .FRAME CatchSignalsPlease
  374. .TITLE Signal handler
  375. */
  376. CatchSignalsPlease(action)
  377. int    (*action)();
  378.   {
  379.     if( signal(SIGINT,  SIG_IGN) != SIG_IGN ) signal(SIGINT,  action);
  380.     if( signal(SIGQUIT, SIG_IGN) != SIG_IGN ) signal(SIGQUIT, action);
  381.     if( signal(SIGHUP,  SIG_IGN) != SIG_IGN ) signal(SIGHUP,  action);
  382.   }
  383.  
  384. /*
  385. .FRAME List
  386. .TITLE Produce list
  387. */
  388. List()
  389.   {
  390.     register int    bp;
  391.     register char    *bufp;
  392.     char        buffer[256];
  393.  
  394.     NewFile();
  395.     bp = Braces = 0;
  396.     InString = InComment = 0;        /* reset for new file -DV */
  397.     SawFunction = 0;
  398.     bufp = buffer;
  399.     while( fgets(bufp, sizeof(buffer), File) != NULL )
  400.       {
  401.         ++FileLineNumber;
  402.         if( bp )  NewFunction();
  403.  
  404.         if( ++LineNumber >= PageEnd ) NewPage();
  405.  
  406.         if( bufp[0] == '\f'
  407.          && bufp[1] == '\n'
  408.          && bufp[2] == '\0' ) NewPage(); /* was strcpy(bufp, "^L\n");*/
  409.  
  410.         if( NumberFlag )
  411.           {
  412.             if( *bufp == '\n' )
  413.                 printf("        ");
  414.             else
  415.                 printf("%6ld  ", FileLineNumber);
  416.           }
  417.         if( (Braces == 0) &&  LooksLikeFunction(bufp) )
  418.             AddToTableOfContents(NEWFUNCTION);
  419.  
  420.         bp = PutLine(buffer);
  421.       }
  422.   }
  423.  
  424. /*
  425. .FRAME PutLine
  426. .TITLE Output line
  427. */
  428. PutLine(l)
  429. register char    *l;
  430.   {
  431.     extern   char    *EndComment();
  432.     extern   char    *EndString();
  433.     register char    c;
  434.     int        bp;
  435.     char        *save;
  436.  
  437.     bp = 0;
  438.     for( save = l; c = *l; ++l )
  439.         if( InComment ) 
  440.             l = EndComment(l);
  441.         else if( InString )
  442.             l = EndString(l);
  443.         else
  444.             switch(c)
  445.               {
  446.                 case '{':
  447.                 ++Braces;
  448.                 break;
  449.     
  450.                 case '}':
  451.                 if( --Braces == 0 )
  452.                     bp = 1;
  453.                 break;
  454.  
  455.                 case '\'':
  456.                 for( ++l; *l && *l != '\''; ++l )
  457.                     if( *l == '\\' && *(l+1) ) ++l;
  458.                 break;
  459.             
  460.                 case '"':
  461.                 InString = 1;
  462.                 break;
  463.  
  464.                 case '/':
  465.                 if( *(l+1) == '*' )
  466.                   {
  467.                     InComment = 1;
  468.                     ++l;
  469.                   }
  470.                 break;
  471.               }
  472.     printf("%s", save);
  473.     return(bp);
  474.   }
  475.  
  476. /*
  477. .FRAME EndComment
  478. .TITLE End of comment
  479. */
  480. char *
  481. EndComment(p)
  482. register char    *p;
  483.   {
  484.     register char    c;
  485.  
  486.     /*
  487.      * Always return pointer to last non-null char looked at.
  488.      */
  489.     while( c = *p++ )
  490.         if( c == '*' && *p == '/' )
  491.           {
  492.             InComment = 0;
  493.             return(p);
  494.           }
  495.     return(p-2);
  496.   }
  497.  
  498. /*
  499. .FRAME EndString
  500. .TITLE End of string
  501. */
  502. char *
  503. EndString(p)
  504. register char    *p;
  505.   {
  506.     register char    c;
  507.  
  508.     /*
  509.      * Always return pointer to last non-null char looked at.
  510.      */
  511.     while( c = *p++ )
  512.         if( c == '\\' && *p )
  513.           {
  514.             ++p;
  515.             continue;
  516.           }
  517.         else if( c == '"' )
  518.           {
  519.             InString = 0;
  520.             return(p-1);
  521.           }
  522.     return(p-2);
  523.   }
  524.  
  525. /*
  526. .FRAME NewFunction
  527. .TITLE Process new function
  528. */
  529. NewFunction()
  530.   {
  531.     register int    i;
  532.  
  533.     if( Space_to_leave <= 0 || !SawFunction ) return;
  534.     if( LineNumber + Space_to_leave  > (PageLength * PagePart / 16) )
  535.         NewPage();
  536.     else
  537.       {
  538.         for( i=0; i < (Space_to_leave); ++i ) putchar('\n');
  539.         LineNumber += Space_to_leave;
  540.       }
  541.  
  542.     SawFunction = 0;
  543.   }
  544.  
  545. #define HEADER_SIZE 3
  546.  
  547. /*
  548. .FRAME NewPage
  549. .TITLE Start new page
  550. */
  551. NewPage()
  552.   {
  553.     if( PageNumber >= 0 ) ++PageNumber;
  554.     putchar(BP);
  555.     LineNumber = 0;
  556.  
  557.     PutHeader();
  558.   }
  559.  
  560. /*
  561. .FRAME PutHeader
  562. .TITLE Output header
  563. */
  564. PutHeader()
  565.   {
  566.     register int    i, l, j;
  567.  
  568.     putchar('\n');
  569.     ++LineNumber;
  570.     l = strlen(CurrentName);
  571.     for( j=0; j < l; ++j )
  572.         printf("%c\b%c\b%c", CurrentName[j], CurrentName[j], CurrentName[j]);
  573.  
  574.     if( PageNumber > 0 )
  575.       {
  576.         printf("  %.17s", FileDate);
  577.         GoToColumn(l+19, 70);
  578.         printf("Page:%4d\n\n", PageNumber);
  579.         ++LineNumber;
  580.         ++LineNumber;
  581.       }
  582.     else
  583.       {
  584.         GoToColumn(l, 55);
  585.         printf("%s\n\n", Today);
  586.         ++LineNumber;
  587.         ++LineNumber;
  588.       }
  589.   }
  590.  
  591. /*
  592. .FRAME GoToColumn
  593. .TITLE Tabulate
  594. */
  595. GoToColumn(from, to)
  596. register int    from, to;
  597.   {
  598.     if( from < to)
  599.       {
  600.         if( TabWidth > 0 ){
  601.             from &= ~(TabWidth-1);
  602.             for( ; (from + TabWidth) <= to; from += TabWidth )
  603.                 putchar('\t');
  604.         }
  605.         for( ; from < to; from++ )
  606.             putchar(' ');
  607.       }
  608.   }
  609. /*
  610. .FRAME LooksLikeFunction
  611. .TITLE Function definition
  612. */
  613. LooksLikeFunction(s)
  614. register char    *s;
  615.   {
  616.     register char    *p;
  617.     register int    i;
  618.     char        *save;
  619.  
  620.     if( InComment || InString ) return(0);
  621.  
  622.     save = s;
  623.  
  624.     i = 0;
  625.     do
  626.     {
  627.        p = FunctionName;
  628.  
  629.        if( *s == '*' ) ++s;
  630.        if( (*s != '_') && !isalpha(*s) ) return(0);
  631.  
  632.        while( isidchr(*s) )
  633.            *p++ = *s++;
  634.        *p = '\0';
  635.  
  636.        while( (*s == ' ') || (*s == '\t') ) ++s;
  637.        i++;
  638.     }
  639.     while ( *s && *s != '(' && i < 4 );
  640.  
  641.     if( *s != '(' || *(s+1) == '*' ) return(0);
  642.  
  643.     for (i = 0; *s; s++)
  644.       {
  645.         switch( *s )
  646.           {
  647.             case '(':
  648.             ++i;
  649.             continue;
  650.  
  651.             case ')':
  652.             --i;
  653.             break;
  654.  
  655.             default:
  656.             break;
  657.           }
  658.           if( i == 0 ) break;
  659.       }
  660.     if( !*s ) return(0);
  661.  
  662.     while( *s )
  663.       {
  664.         if( *s == '{') break;
  665.         if( *s == ';' || *s == ':' ) return(0);
  666.         ++s;
  667.       }
  668.  
  669.     /*
  670.      * This will cause the function name part of the line to
  671.      * be double striken.  Note that this assumes the name and the opening
  672.      * parentheses are on the same line...
  673.      */
  674.  
  675.     if( p = strchr( save, '(' ) )
  676.     {
  677.        p--;
  678.        while( p != save && isidchr( *(p-1) ) ) p--;
  679.        for( i=0; save != p; save++, i++ ) putchar(' ');
  680.        for( ; *p != '('; p++, i++ )       putchar( *p );
  681.     }
  682.     else
  683.        for( i=0; *save && (*save == '*' || isidchr(*save)); ++i, ++save)
  684.         if( *save == '*' )
  685.             putchar(' ');
  686.         else
  687.             putchar(*save);
  688.  
  689.     while( i --> 0 ) putchar('\b');
  690.  
  691.     SawFunction = 1;
  692.     return(1);
  693.   }
  694.  
  695. /*
  696. .FRAME AddToTableOfContents
  697. .TITLE Add To Table Of Contents
  698. */
  699. AddToTableOfContents(type)
  700.   {
  701.     if( TocCount > TOC_SIZE )
  702.         return;
  703.     if( TocCount == TOC_SIZE )
  704.       {
  705.         fprintf(stderr, "%s: More than %d Table of contents entries; others ignored.\n",
  706.             ProgName, TOC_SIZE);
  707.         ++TocCount;
  708.         return;
  709.       }
  710.  
  711.     if( type == NEWFILE )
  712.         AddFile();
  713.     else
  714.         AddFunction();
  715.   }
  716.  
  717. /*
  718. .FRAME AddFunction
  719. .TITLE Add function to table of contents
  720. */
  721. AddFunction()
  722.   {
  723.     register int    l;
  724.     register char    *p;
  725.  
  726.     /* This heuristic stops multiple occurrences of a function,
  727.      * selected by #ifdefs, to all end up many times over in the
  728.      * Table of Contents.  One only needs to see it once.  -IAN!
  729.      */
  730.     if( TocCount > 0 && TocPages[TocCount-1] == PageNumber
  731.         && strcmp(Toc[TocCount-1],FunctionName) == 0 )
  732.         return;
  733.     l = strlen(FunctionName);
  734.     p = Toc[TocCount] = (char *)malloc(l+1);
  735.     strcpy(p, FunctionName);
  736.     TocPages[TocCount] = PageNumber;
  737.     ++TocCount;
  738.   }
  739.  
  740. /*
  741. .FRAME AddFile
  742. .TITLE Add file to table of contents
  743. */
  744. AddFile()
  745.   {
  746.     register int    i, l;
  747.     register int    len;
  748.     char        temp[20];
  749.  
  750.     len = strlen(CurrentName) + 20;
  751.     len = (len < 130) ? 130 : len;
  752.     Toc[TocCount] = (char *)malloc(len);
  753.     sprintf(Toc[TocCount], "\n    File: %s ", CurrentName);
  754.     l = strlen(Toc[TocCount]);
  755.     if( l < 64 )
  756.       {
  757.         if( TabWidth > 0 ){
  758.             i = ((64 - l) / TabWidth) + 1;
  759.             while( i-- > 0 )
  760.                 Toc[TocCount][l++] = '\t';
  761.         }
  762.         else{
  763.             while( l < 64 )
  764.                 Toc[TocCount][l++] = ' ';
  765.         }
  766.         Toc[TocCount][l++] = '\0';
  767.       }
  768.     sprintf(temp, "  Page %4d\n", PageNumber);
  769.     strcat(Toc[TocCount], temp);
  770.     ++TocCount;
  771.   }
  772.  
  773. /*
  774. .FRAME NewFile
  775. .TITLE Start next file
  776. */
  777. NewFile()
  778.   {
  779.     GetFileTime();
  780.     NewPage();
  781.     AddToTableOfContents(NEWFILE);
  782.     FileLineNumber = 0;
  783.   }
  784.  
  785. /*
  786. .FRAME GetFileTime
  787. .TITLE Get the file modification time
  788. */
  789. GetFileTime()
  790.   {
  791.     struct stat    st;
  792.  
  793.     if( File == stdin )
  794.         strncpy(FileDate, &Today[4], 20);
  795.     else
  796.       {
  797.         fstat(fileno(File), &st);
  798.         strncpy(FileDate, ctime(&st.st_mtime) + 4, 20);
  799.       }
  800.     strncpy(&FileDate[12], &FileDate[15], 5);
  801.     FileDate[18] = '\0';
  802.   }
  803.  
  804. /*
  805. .FRAME DumpTableOfContents
  806. .TITLE Outputs table of contents
  807. */
  808. DumpTableOfContents()
  809.   {
  810.     register int    i, j;
  811.     int         index[TOC_SIZE];
  812.  
  813.     if( TocCount == 0 ) return;
  814.  
  815.     for (i = 0; i < TocCount; i++) index[i] = i;
  816.     if( SortFlag )
  817.         SortTable(index);
  818.  
  819.     CurrentName = "Table of  Contents";
  820.  
  821.     PageNumber = -1;
  822.     LineNumber = 0;
  823.     NewPage();
  824.  
  825.     for( i=0; i < TocCount; ++i )
  826.       {
  827.         if( Toc[index[i]][0] == '\n' )
  828.           {
  829.             if( (LineNumber + 5) >= PageEnd ) NewPage();
  830.  
  831.             printf("%s", Toc[index[i]]);
  832.             LineNumber += 2;
  833.             continue;
  834.           }
  835.         if( ++LineNumber >= PageEnd ) NewPage();
  836.  
  837.         printf("        %s ", Toc[index[i]]);
  838.         for( j=strlen(Toc[index[i]]); j < 48; ++j ) putchar('.');
  839.         printf(" %4d\n", TocPages[index[i]]);
  840.       }
  841.   }
  842.  
  843. /*
  844. .FRAME SortTable
  845. .TITLE Sorts table of contents
  846. */
  847. SortTable(index)
  848. register int    *index;
  849.   {
  850.     register int    i, temp, flag;
  851.  
  852.     do {
  853.         flag = 0;
  854.         for (i = 0; i < TocCount - 1; i++)
  855.           {
  856.             if( Toc[index[i]][0] == '\n' || Toc[index[i+1]][0] == '\n' )
  857.                 continue;       /* don't sort across file names */
  858.             if( strcmp(Toc[index[i]], Toc[index[i+1]]) > 0)
  859.               {
  860.                 temp       = index[i];
  861.                 index[i]   = index[i+1];
  862.                 index[i+1] = temp;
  863.                 flag       = 1;
  864.               }
  865.           }
  866.     } while( flag );
  867.   }
  868. /*
  869. .REMARK
  870.     END OF SOURCE PROGRAM
  871. */
  872.  
  873.